﻿/*
 * Copyright (c) 2011 Shawn Rakowski
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to 
 * deal in the Software without restriction, including without limitation the 
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
 * sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE. 
 * 
 */

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;

namespace ROS.Persistence.DAO.MySQLDAO
{
    internal class MySQLDAOCmdExecuter<T>
    {
        private MySQLDAO dao;

        public MySQLDAOCmdExecuter(MySQLDAO mysqlDAO)
        {
            this.dao = mysqlDAO;
        }

        /// <summary>
        /// Gets the last ID inserted into the database.
        /// </summary>
        /// <returns></returns>
        internal long GetLastID()
        {
            MySqlCommand lastID = dao.DB.CreateCommand();
            lastID.CommandText = "SELECT LAST_INSERT_ID()";
            return (long)lastID.ExecuteScalar();
        }

        /// <summary>
        /// Delegate for handling when the data reader is loaded with a new record during the
        /// PerformSelectQuery method.
        /// </summary>
        /// <param name="dataReader"></param>
        /// <param name="context"></param>
        internal delegate T LoadDTODelegate(MySqlDataReader dataReader);

        /// <summary>
        /// Performs a singleton (returns 1 record) SQL select statement 
        /// (or anything that reads data into a DataReader object).
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        internal T PerformSingletonSelectQuery(String sql,
                                                Dictionary<String, object> parameters,
                                                LoadDTODelegate callback)
        {
            IList<T> dataTransferObjectList = PerformSelectQuery(sql, parameters, callback);
            T dto = default(T);
            if (dataTransferObjectList.Count == 1)
            {
                dto = dataTransferObjectList[0];
            }
            else if (dataTransferObjectList.Count > 0)
            {
                throw new Exception("Expected single result from query, got multiple");
            }
            return dto;
        }

        /// <summary>
        /// Performs a SQL select statement (or anything that reads data into a DataReader object).
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        internal IList<T> PerformSelectQuery(String sql, Dictionary<String, object> parameters,
                                              LoadDTODelegate callback)
        {
            Debug.Assert(!String.IsNullOrWhiteSpace(sql), "Empty SQL statement received");

            MySqlCommand cmd = dao.DB.CreateCommand();
            cmd.CommandText = sql;
            if (parameters != null)
            {
                foreach (String key in parameters.Keys)
                {
                    cmd.Parameters.AddWithValue(key, parameters[key]);
                }
            }

            MySqlDataReader dataReader = cmd.ExecuteReader();
            IList<T> dtoList = new List<T>();
            while (dataReader.Read())
            {
                dtoList.Add(callback(dataReader));
            }

            dataReader.Close();
            return dtoList;
        }

        /// <summary>
        /// Perform an SQL insert statement against the MySQL database returning the last ID entered.
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns>The last ID entered</returns>
        internal long PerformInsertNonQuery(String sql, Dictionary<String, object> parameters)
        {
            PerformNonQuery(sql, parameters);
            return GetLastID();
        }

        /// <summary>
        /// Perform an SQL statement against the MySQL database. These are things like inserts,
        /// updates, and delete.
        /// </summary>
        /// <param name="deleteSQL">The SQL statement to execute.</param>
        /// <param name="parameters">A list of parameters to the delete statement.</param>
        internal void PerformNonQuery(String sql, Dictionary<String, object> parameters)
        {
            Debug.Assert(!String.IsNullOrWhiteSpace(sql), "Empty SQL statement received");

            MySqlCommand cmd = dao.DB.CreateCommand();
            cmd.CommandText = sql;
            if (parameters != null)
            {
                foreach (String key in parameters.Keys)
                {
                    cmd.Parameters.AddWithValue(key, parameters[key]);
                }
            }
            cmd.ExecuteNonQuery();
        }
    }
}
